<!--
 * @Description: 热区-右侧配置栏
 * @Autor: HuiSir<273250950@qq.com>
 * @Date: 2021-08-16 14:56:08
 * @LastEditTime: 2021-08-19 15:43:42
-->
<template>
    <div id="QSuperHotView">
        <h2>{{iconDes}}</h2>
        <el-form :module="props" label-width="80px" label-position="left">
            <el-form-item label="选择图片">
                <ImgUpload @success="bgImgSuc" :currImg="props.backgroundImage" />
            </el-form-item>
            <el-form-item label="开始时间">
                <el-date-picker type="datetime" placeholder="选择时间" v-model="props.startTime"
                    style="width: 100%;"></el-date-picker>
            </el-form-item>
            <el-form-item label="结束时间">
                <el-date-picker type="datetime" placeholder="选择时间" v-model="props.endTime"
                    style="width: 100%;"></el-date-picker>
            </el-form-item>
            <el-form-item>
                <el-button :disabled="!props.backgroundImage" type="warning"
                    @click="showEditBox = true" icon="el-icon-crop"
                    style="width:100%;border-color:#FE8B3E;color:#FE8B3E;background:#fff;" plain>
                    绘制热区
                </el-button>
            </el-form-item>
        </el-form>
        <!-- 绘制热区弹窗 -->
        <el-dialog title="绘制热区" width="1200px" top="calc(10vh - 53px)" :visible.sync="showEditBox"
            custom-class="edit-box">
            <div class="left">
                <!-- 背景 -->
                <img :src="props.backgroundImage" @load="bgOnload">
                <!-- 画布 -->
                <div class="canvas" @contextmenu.prevent="canvasMousedown"
                    @mousedown.prevent="canvasMousedown" :style="{height:canvasSize[1]+'px'}">
                    <!-- 缓存热区 -->
                    <div v-show="canvasMouseEnter" class="area cache" :style="cacheAreaStyle"></div>
                    <!-- 热区渲染 -->
                    <div v-for="(item,index) in props.area" :key="item.id"
                        :class="{area:true,act:index==activeAreaIndex}" :style="areaStyle(item)"
                        :data-index="index" @mousedown.prevent="areaMousedown">
                        热区{{index+1}}
                        <!-- 缩放锚点 -->
                        <template v-if="index==activeAreaIndex">
                            <div v-for="anchor in 8" :key="anchor"
                                :class="`anchor anchor-${anchor}`" :data-index="index"
                                :data-anchor="anchor" @mousedown.prevent="anchorMousedown"></div>
                        </template>
                    </div>
                </div>
            </div>
            <div class="right">
                <div class="intro">
                    <h3>操作说明</h3>
                    <div class="text">
                        请用鼠标在左侧图片区，按住左键拖拽画出区域构成热区，通过增加链接进行跳转，重叠部分下层区域无法进行点击。
                    </div>
                </div>
                <div class="statistics">
                    <div class="text">单个图片最多支持 10 个热区划分</div>
                    <div class="count">{{props.area.length}}/10</div>
                </div>
                <el-table ref="areasTable" :data="props.area" height="calc(80vh - 158px)"
                    max-height="479" border style="width: 100%;" highlight-current-row
                    @row-click="areasTableRowClick">
                    <el-table-column type="index" label="序号" width="100" align="center">
                    </el-table-column>
                    <el-table-column prop="linkData" label="链接" align="center">
                        <template slot-scope="scope">
                            <q-link :select-data="{id:scope.$index+'',linkData:scope.row.linkData}"
                                link-style="width:100%;height:28px;"
                                :linkText="scope.row.linkData?'重新选择':'选择链接'"
                                @link-data="handleLinkData">
                            </q-link>
                        </template>
                    </el-table-column>
                    <el-table-column label="操作" width="100" align="center">
                        <template slot-scope="scope">
                            <el-button @click="delArea(scope.$index)" size="mini">删除</el-button>
                        </template>
                    </el-table-column>
                </el-table>
            </div>
        </el-dialog>
    </div>
</template>

<script>
import ImgUpload from './imgupload.vue'
import QLink from '@/views/template/components/link'
export default {
    name: 'QSuperHotView',
    components: { ImgUpload, QLink },
    props: {
        id: String,
        props: Object,
        iconDes: String,
    },
    data() {
        return {
            showEditBox: false,
            canvasMouseEnter: false,
            areaMouseEnter: false,
            anchorMouseEnter: false,
            canvasSize: [0, 0],
            cacheAreaPos: [0, 0],
            cacheWinPos: [0, 0],
            cacheAreaStyle: {},
            activeAreaIndex: null,
            copyCurrArea: null,
            curAnchor: null,
        }
    },
    watch: {
        props: {
            handler() {
                const { id, props } = this
                this.$store.commit('CHANGE_COMPONENT', {
                    id,
                    props,
                })
            },
            deep: true,
        },
        showEditBox(val) {
            if (val) {
                // 注册鼠标全局事件
                window.addEventListener('mouseup', this.domMouseup, false)
                window.addEventListener('mousemove', this.domMousemove, false)
            } else {
                window.removeEventListener('mouseup', this.domMouseup)
                window.removeEventListener('mousemove', this.domMousemove)
            }
        },
    },
    methods: {
        /* 渲染单个热区位置 */
        areaStyle(item) {
            return {
                left: item.left,
                top: item.top,
                width: item.width,
                height: item.height,
            }
        },

        /* 删除热区 */
        delArea(index) {
            this.props.area.splice(index, 1)
        },

        /* 背景图上传 */
        bgImgSuc(imgUrl) {
            this.props.backgroundImage = imgUrl
        },

        /* 背景图加载 */
        bgOnload({ path }) {
            // 记录实际尺寸
            this.canvasSize = [path[0].width, path[0].height]
        },

        /* 跳转连接 */
        handleLinkData(linkData) {
            this.props.area[linkData.id].linkData = linkData
        },

        /* 画布-鼠标按下 */
        canvasMousedown({ type, button, offsetX, offsetY, clientX, clientY, target }) {
            //非鼠标左键return,屏蔽右键菜单
            if (button != 0) {
                return false
            }
            // 目标元素非画布
            if (target.className != 'canvas') {
                return false
            }

            //鼠标状态改变
            this.canvasMouseEnter = type == 'mousedown'

            //记录鼠标位置
            this.cacheAreaPos = [offsetX, offsetY]
            this.cacheWinPos = [clientX, clientY]
        },

        /* 热区-鼠标按下 */
        areaMousedown({ type, button, target, clientX, clientY }) {
            if (button != 0) {
                return false
            }

            // 目标元素非热区
            if (!target.className.includes('area')) {
                return false
            }

            const { index } = target.dataset

            // 激活热区
            this.activeAreaIndex = index
            this.$refs.areasTable.setCurrentRow(this.props.area[index])

            //状态改变
            this.areaMouseEnter = type == 'mousedown'

            //记录鼠标位置
            this.cacheWinPos = [clientX, clientY]

            //拷贝当前热区
            this.copyCurrArea = JSON.parse(JSON.stringify(this.props.area[index]))
        },

        /* Resize锚点事件绑定 */
        anchorMousedown({ type, button, clientX, clientY, target }) {
            const { index, anchor } = target.dataset
            if (button != 0) return false //非鼠标左键return
            //状态改变
            this.anchorMouseEnter = type == 'mousedown'
            //记录鼠标位置
            this.cacheWinPos = [clientX, clientY]
            //记录当前锚点
            this.curAnchor = anchor
            //拷贝热区
            this.copyCurrArea = JSON.parse(JSON.stringify(this.props.area[index]))
        },

        /* 全局-鼠标移动 */
        domMousemove({ button, clientX, clientY }) {
            if (button != 0) {
                return false
            }
            let {
                canvasMouseEnter,
                cacheAreaPos,
                cacheWinPos,
                areaMouseEnter,
                activeAreaIndex,
                anchorMouseEnter,
                curAnchor,
                curAnchorAreaPosReset,
                curAnchorAreaSizeReset,
            } = this

            // 绘制
            if (canvasMouseEnter) {
                let width = Math.abs(clientX - cacheWinPos[0]) + 'px',
                    height = Math.abs(clientY - cacheWinPos[1]) + 'px',
                    left =
                        (clientX >= cacheWinPos[0]
                            ? cacheAreaPos[0]
                            : cacheAreaPos[0] - Math.abs(clientX - cacheWinPos[0])) + 'px',
                    top =
                        (clientY >= cacheWinPos[1]
                            ? cacheAreaPos[1]
                            : cacheAreaPos[1] - Math.abs(clientY - cacheWinPos[1])) + 'px'

                this.cacheAreaStyle = {
                    width,
                    height,
                    left,
                    top,
                }
                return
            }

            // 拖拽
            if (areaMouseEnter) {
                let currArea = this.props.area[activeAreaIndex]
                // 位置调整
                curAnchorAreaPosReset({ x: true, y: true, currArea, clientX, clientY })
                // 视图更新
                this.$set(this.props.area, activeAreaIndex, currArea)
                return
            }

            //图层缩放（锚点事件）
            if (anchorMouseEnter) {
                let currArea = this.props.area[activeAreaIndex]

                //根据不同锚点执行不同运算
                switch (Number(curAnchor)) {
                    case 1:
                        curAnchorAreaSizeReset({ w: '-', h: '-', currArea, clientX, clientY })
                        curAnchorAreaPosReset({ x: true, y: true, currArea, clientX, clientY })
                        break
                    case 2:
                        curAnchorAreaSizeReset({ h: '-', currArea, clientX, clientY })
                        curAnchorAreaPosReset({ x: false, y: true, currArea, clientX, clientY })
                        break
                    case 3:
                        curAnchorAreaSizeReset({ w: '+', h: '-', currArea, clientX, clientY })
                        curAnchorAreaPosReset({ x: false, y: true, currArea, clientX, clientY })
                        break
                    case 4:
                        curAnchorAreaSizeReset({ w: '-', currArea, clientX, clientY })
                        curAnchorAreaPosReset({ x: true, y: false, currArea, clientX, clientY })
                        break
                    case 5:
                        curAnchorAreaSizeReset({ w: '+', currArea, clientX, clientY })
                        break
                    case 6:
                        curAnchorAreaSizeReset({ w: '-', h: '+', currArea, clientX, clientY })
                        curAnchorAreaPosReset({ x: true, y: false, currArea, clientX, clientY })
                        break
                    case 7:
                        curAnchorAreaSizeReset({ h: '+', currArea, clientX, clientY })
                        break
                    default:
                        curAnchorAreaSizeReset({ w: '+', h: '+', currArea, clientX, clientY })
                        break
                }

                //视图更新
                this.$set(this.props.area, activeAreaIndex, currArea)
            }
        },

        /* 全局鼠标离开 */
        domMouseup({ button }) {
            if (button != 0) {
                return false
            }

            const {
                canvasMouseEnter,
                cacheAreaStyle,
                canvasSize,
                areaMouseEnter,
                anchorMouseEnter,
            } = this

            // 绘制结束
            if (canvasMouseEnter) {
                // 插入热区
                if (cacheAreaStyle.width != 0 && cacheAreaStyle.height != 0) {
                    if (this.props.area.length < 10) {
                        // 插入到prop
                        this.props.area.push({
                            left:
                                ((parseInt(cacheAreaStyle.left) / canvasSize[0]) * 100).toFixed(2) +
                                '%',
                            top:
                                ((parseInt(cacheAreaStyle.top) / canvasSize[1]) * 100).toFixed(2) +
                                '%',
                            width:
                                ((parseInt(cacheAreaStyle.width) / canvasSize[0]) * 100).toFixed(
                                    2
                                ) + '%',
                            height:
                                ((parseInt(cacheAreaStyle.height) / canvasSize[1]) * 100).toFixed(
                                    2
                                ) + '%',
                            linkData: null,
                            id: Date.now(),
                        })
                        // 激活热区
                        this.activeAreaIndex = this.props.area.length - 1
                    } else {
                        this.$message({
                            type: 'warning',
                            message: '单个图片最多支持 10 个热区!',
                        })
                    }
                }

                // 状态恢复
                this.canvasMouseEnter = false
                this.cacheAreaStyle = {
                    left: 0,
                    top: 0,
                    width: 0,
                    height: 0,
                }
                this.cacheAreaPos = [0, 0]
                this.cacheWinPos = [0, 0]
            }

            // 拖拽结束
            if (areaMouseEnter) {
                this.areaMouseEnter = false
                this.cacheWinPos = [0, 0]
                this.copyCurrArea = null
            }

            // 尺寸调整结束
            if (anchorMouseEnter) {
                this.anchorMouseEnter = false
                this.cacheWinPos = [0, 0]
                this.curAnchor = null
                this.copyCurrArea = null
            }
        },

        /* 热区位置调整 */
        curAnchorAreaPosReset({ x, y, currArea, clientX, clientY }) {
            const { copyCurrArea, cacheWinPos, canvasSize } = this
            currArea.left = x
                ? (
                      parseFloat(copyCurrArea.left) +
                      ((clientX - cacheWinPos[0]) / canvasSize[0]) * 100
                  ).toFixed(2) + '%'
                : copyCurrArea.left

            currArea.top = y
                ? (
                      parseFloat(copyCurrArea.top) +
                      ((clientY - cacheWinPos[1]) / canvasSize[1]) * 100
                  ).toFixed(2) + '%'
                : copyCurrArea.top
        },

        /* 热区尺寸调整 */
        curAnchorAreaSizeReset({ w, h, currArea, clientX, clientY }) {
            const { copyCurrArea, cacheWinPos, canvasSize } = this
            const widthStr = w
                ? `currArea.width = (parseFloat(copyCurrArea.width) ${w} (clientX - cacheWinPos[0])/ canvasSize[0] * 100).toFixed(2) + '%';`
                : ''
            const heightStr = h
                ? `currArea.height = (parseFloat(copyCurrArea.height) ${h} (clientY - cacheWinPos[1])/ canvasSize[1] * 100).toFixed(2) + '%';`
                : ''
            eval(widthStr + heightStr) //字符串运行
        },

        /* 列表行点击 */
        areasTableRowClick({ id }) {
            this.activeAreaIndex = this.props.area.findIndex((item) => item.id == id)
        },
    },
}
</script>

<style lang="scss" scoped>
@import '../../../styles/base';
#QSuperHotView {
    padding: 18px;
    h2 {
        margin: 0;
        font-size: 18px;
        line-height: 25px;
        color: #101010;
        padding-bottom: 18px;
        border-bottom: 1px solid #e9e9e9;
        margin-bottom: 20px;
    }
}
.edit-box {
    .left {
        float: left;
        width: 55%;
        height: 80vh;
        overflow-y: auto;
        position: relative;
        img {
            width: 100%;
            height: auto;
            user-select: none;
            pointer-events: none;
        }
        .canvas {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            .area {
                position: absolute;
                border: 1px solid #418af1;
                display: flex;
                justify-content: flex-end;
                align-items: flex-end;
                font-size: 14px;
                color: rgba(255, 255, 255, 0.9);
                word-break: keep-all;
                cursor: pointer;
                &.act,
                &.cache {
                    background: rgba(65, 138, 241, 0.22);
                    cursor: move;
                }
                .anchor {
                    position: absolute;
                    width: 5px;
                    height: 5px;
                    background: #418af1;
                    z-index: 5;
                    &.anchor-1,
                    &.anchor-2,
                    &.anchor-3 {
                        top: -3px;
                    }
                    &.anchor-1,
                    &.anchor-4,
                    &.anchor-6 {
                        left: -3px;
                    }
                    &.anchor-2,
                    &.anchor-7 {
                        left: calc(50% - 3px);
                    }
                    &.anchor-3,
                    &.anchor-5,
                    &.anchor-8 {
                        right: -3px;
                    }
                    &.anchor-4,
                    &.anchor-5 {
                        top: calc(50% - 3px);
                    }
                    &.anchor-6,
                    &.anchor-7,
                    &.anchor-8 {
                        bottom: -3px;
                    }
                    &.anchor-3,
                    &.anchor-6 {
                        cursor: ne-resize;
                    }
                    &.anchor-1,
                    &.anchor-8 {
                        cursor: nw-resize;
                    }
                    &.anchor-2,
                    &.anchor-7 {
                        cursor: n-resize;
                    }
                    &.anchor-4,
                    &.anchor-5 {
                        cursor: w-resize;
                    }
                }
            }
        }
    }
    .right {
        float: right;
        width: calc(45% - 20px);
        height: 80vh;
        .intro {
            h3 {
                color: #333333;
                font-size: 22px;
                line-height: 30px;
                margin: 0;
            }
            .text {
                font-size: 16px;
                line-height: 24px;
                color: #666666;
                margin-top: 7px;
            }
        }
        .statistics {
            display: flex;
            justify-content: space-between;
            font-size: 16px;
            line-height: 24px;
            margin-top: 34px;
            margin-bottom: 15px;
            .text {
                color: #c7c7c7;
            }
            .count {
                color: #333333;
            }
        }
    }
}
</style>
<style lang="scss">
.edit-box .el-dialog__body {
    overflow: hidden;
    padding-bottom: 20px;
}
</style>
